/**
 * 
 */
package name.marz.to.go.btree.node;

import java.util.Map;
import java.util.TreeMap;

/**
 * NodeのTreeMapによる実装。
 * TreeMapの仕様の関係上、重複するキーの登録は出来ない。（上書きされる）
 * @author masaru-gotou
 *
 */
public class TreeMapNode extends AbstractNode {
	private TreeMap<Key, Object> keyPointerPair;
	private int keycount;
	
	TreeMapNode() {
		this.keycount = 4;
		keyPointerPair = new TreeMap<Key, Object>();
	}
	
	TreeMapNode(int keycount) {
		this.keycount = keycount;
		keyPointerPair = new TreeMap<Key, Object>();
	}
	/* (non-Javadoc)
	 * @see btree.node.AbstractNode#add(btree.node.Key, java.lang.Object)
	 */
	@Override
	public void add(Key key, Object pointer) throws NodeOverflowException {
		if ( keyPointerPair.size() >= keycount ) throw new NodeOverflowException();
		keyPointerPair.put(key, pointer);
	}

	/* (non-Javadoc)
	 * @see btree.node.AbstractNode#clear()
	 */
	@Override
	public void clear() {
		keyPointerPair.clear();
	}

//	/* (non-Javadoc)
//	 * @see btree.node.AbstractNode#newNode()
//	 */
//	@Override
//	public Node newNode() {
//		return new TreeMapNode(keycount);
//	}

	/* (non-Javadoc)
	 * @see btree.node.Node#getFirstKey()
	 */
	@Override
	public Key getFirstKey() {
		return keyPointerPair.firstKey();
	}

	/* (non-Javadoc)
	 * @see btree.node.Node#getKey(int)
	 */
	@Override
	public Key getKey(int index) {
		if ( index >= keycount ) throw new ArrayIndexOutOfBoundsException(index);
		if ( index >= keyPointerPair.size() ) return null;
		return (Key)keyPointerPair.keySet().toArray()[index];
	}

	/* (non-Javadoc)
	 * @see btree.node.Node#getKeyCount()
	 */
	@Override
	public int getKeyCount() {
		return keyPointerPair.size();
	}

	/* (non-Javadoc)
	 * @see btree.node.Node#getPointer(btree.node.Key)
	 */
	@Override
	public Object getPointer(Key key) {
		Map.Entry<Key, Object> entry = keyPointerPair.floorEntry(key);
		return entry == null ? leftPointer : entry.getValue();
	}

	/* (non-Javadoc)
	 * @see btree.node.Node#getPointer(int)
	 */
	@Override
	public Object getPointer(int index) {
		if ( index >= keycount ) throw new ArrayIndexOutOfBoundsException(index);
		if ( index >= keyPointerPair.size() ) return null;
		return keyPointerPair.values().toArray()[index];
	}

	/* (non-Javadoc)
	 * @see btree.node.Node#hasKey(btree.node.Key)
	 */
	@Override
	public boolean hasKey(Key key) {
		return keyPointerPair.containsKey(key);
	}

	/* (non-Javadoc)
	 * @see btree.node.Node#isLeaf()
	 */
	@Override
	public boolean isLeaf() {
		for ( Object pointer : keyPointerPair.values() ) {
			if ( pointer instanceof TreeMapNode ) {
				return false;
			}
		}
		return true;
	}

	/* (non-Javadoc)
	 * @see btree.node.Node#size()
	 */
	@Override
	public int getMaxKeys() {
		return keycount;
	}
	@Override
	public void setMaxKeys(int keycount) {
		this.keycount = keycount;
	}
	@Override
	public void remove(Key key) {
		keyPointerPair.remove(key);
	}
	@Override
	public Node split() {
		Node node = this;
		int keycount = node.getMaxKeys();
//		Node larger_node = (Node)node.newNode();
		Node larger_node = NodeFactory.createNode(node.getClass().getName(), node.getMaxKeys());
		// 後半のキーを新しいノードに移す
		for ( int i=keycount/2; i<keycount; i++ ) {
			try {
				larger_node.add(node.getKey(i),node.getPointer(i));
			} catch (NodeOverflowException e) {
				throw new InternalError("split failed");
			}
		}
		// 移された側はクリアする
		for ( int i=0; i<keycount/2; i++ ) {
			node.remove(larger_node.getKey(i));
		}
		return larger_node;
	}

	@Override
	public Object clone() {
		// TODO Auto-generated method stub
		return null;
	}

//	@Override
//	public NodeMemento save() {
//		// TODO Auto-generated method stub
//		return null;
//	}
//
//	@Override
//	public void restore(NodeMemento m) {
//		// TODO Auto-generated method stub
//		
//	}
}
